"""
====start====

#######################
#   Terminal UI API   #
# codng by XCreeperPa #
#######################

Terminal for Windows 用户界面、应用程序接口

依赖：
    第三方：
        qt_material
        PyQt5
    自定义：
        support

架构：
    ==TextWidget== (QPlainTextEdit)
    --文本框控件--
    methods:
        __init__  初始化
        change_text  检查文本
        cursor_position_changed  光标位置改变对应槽函数

    ==MainWindow==
    --主窗口控制，继承自object--
    methods:
        __init__  初始化
        setupUi  设置UI
        startMainTab  主面板设置
        addTaskTab  增加任务面板
        set_up_menus  菜单设置
        MenubarInsertFilepath  菜单栏：插入文件路径
        MenubarInsertFolderPath  菜单栏：插入文件夹路径
        MenubarInsertSymbol  菜单栏：插入符号
        slot_small_tab  tab设置

    ==TextWidgetIndex==
    --文本索引--
    methods:
        __init__  初始化
        __repr__  print支持

    ==Text==
    --文本内容--
    methods:
        __init__  初始化
        setInput  改变输入
        setOutput  改变输出
        setReminder  改变提示
        getInput  获取输入
        getOutput  获取输出
        getReminder  获取提示

    ==Task==
    --任务--
    methods:
        __init__  初始化
        run  运行
        run_again  重新运行
        stop  停止

====end====
"""
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import QPoint
from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import *

from support import *

commands = ('ping', 'explorer')
CommandCompleter(commands)


# 文本索引
class TextWidgetIndex:
    # 初始化
    def __init__(self, block_index: int, str_index: int):
        self.block_index = block_index
        self.str_index = str_index

    # print支持
    def __repr__(self):
        return str(self.block_index) + str(self.str_index)


# 文本内容
class Text:
    # 初始化
    def __init__(self, parent):
        self.blocks = []
        self._input: str = ''
        self._output: str = ''
        self._reminder: list = []
        self._output_index: TextWidgetIndex = TextWidgetIndex(0, 0)
        self._input_index: TextWidgetIndex = TextWidgetIndex(0, 0)
        self._reminder_index: TextWidgetIndex = TextWidgetIndex(0, 0)
        self.parent: TextWidget = parent

    # print支持
    def __repr__(self):
        return self.getValue()

    # 增加提示
    def add_reminder(self, RM):
        self._reminder.append(RM)

    # 文本块切割
    def block_split(self, text):
        self.blocks = []
        block = ''
        for i in text:
            block += i
            if i == '\n':
                self.blocks.append(block)
                block = ''
            elif i == text[-1]:
                self.blocks.append(block)
                break

    # 文本更改
    def change_text(self, text):
        self.block_split(text)
        self.setInput(text[3:], TextWidgetIndex(len(self.blocks), len(text) - 4))
        if (not self.getInput() == '') and (self.getInput()[-1] == '\n'):
            self.parent.task.run(self.getInput(), name='task_test')

    # 获取输出
    def getOutput(self):
        return self._output

    # 获取输入
    def getInput(self):
        return self._input

    # 获取提示
    def getReminder(self):
        return self._reminder

    # 获取值
    def getValue(self):
        return '{}{}{}'.format(self._output, self._input, self._reminder)

    # 获取输出索引
    def get_output_index(self):
        return self._output_index

    # 获取输入索引
    def get_input_index(self):
        return self._input_index

    # 获取提示索引
    def get_reminder_index(self):
        return self._reminder_index

    # 检查是否为输出
    def is_output(self, index: TextWidgetIndex):
        if 0 <= index.block_index <= self.get_output_index().block_index:
            if 0 <= index.str_index <= self.get_output_index().str_index + 1:
                return True
        return False

    # 检查是否为输入
    def is_input(self, index: TextWidgetIndex):
        if self.get_output_index().block_index <= index.block_index <= self.get_input_index().block_index:
            if self.get_output_index().str_index + 1 < index.str_index:
                return True
        return False

    # 检查是否为提示
    def is_reminder(self, index: TextWidgetIndex):
        if self.get_input_index().block_index <= index.block_index <= self.get_reminder_index().block_index:
            if self.get_input_index().block_index <= index.str_index <= self.get_reminder_index().str_index + 1:
                return True
        return False

    # 设置输入
    def setInput(self, value: str, index: TextWidgetIndex):
        self._input = value
        self._input_index = index

    # 设置提示
    def setReminder(self, value: str, index: TextWidgetIndex):
        self._reminder = value
        self._reminder_index = index

    # 设置输出
    def setOutput(self, value, index: TextWidgetIndex):
        self._output = value
        self._output_index = index


# 文本框控件
class TextWidget(QtWidgets.QPlainTextEdit):
    # 初始化
    def __init__(self, parent, task):
        super(TextWidget, self).__init__(parent)
        self.debug = None
        self.text: Text = Text(self)
        self.index_str = self.textCursor().columnNumber()
        self.index_block = self.textCursor().blockNumber()
        self.task = task

        self.textChanged.connect(self.change_text)
        self.text.setOutput('>>>', TextWidgetIndex(0, 2))
        self.text.setInput(' ', TextWidgetIndex(0, 3))
        self.setPlainText(self.text.getValue())
        self.moveCursor(QTextCursor.End)
        self.cursorPositionChanged.connect(self.cursor_position_changed)
        self.textChanged.connect(self.change_text)
        self.setLineWrapMode(QPlainTextEdit.NoWrap)

    # 检查文本
    def change_text(self):
        if isinstance(self.task, Task) and not self.task.state == 'run':
            self.text.change_text(self.toPlainText())

    # 光标位置改变对应槽函数
    def cursor_position_changed(self):
        if not self.task.state == 'run':
            self.text.change_text(self.toPlainText())
            self.index_str = self.textCursor().columnNumber()
            self.index_block = self.textCursor().blockNumber()
            if self.text.is_input(TextWidgetIndex(self.index_block, self.index_str)):
                self.setReadOnly(False)
            else:
                self.setReadOnly(True)
                tc = self.cursorForPosition(QPoint(25, 5))
                tc.insertText(" ")
                self.moveCursor(QTextCursor.Right)
            self.debug = ("is_output:{}\n"
                          "output_block_index:{}\n"
                          "output_str_index:{}\n"
                          "\n"
                          "is_input:{}\n"
                          "input_block_index:{}\n"
                          "imput_str_index:{}\n"
                          "\n"
                          "is_reminder:{}\n"
                          "reminder_block_index:{}\n"
                          "reminder_str_index:{}\n"
                          "\n"
                          "index_block:{}\n"
                          "index_str:{}").format(
                self.text.is_output(TextWidgetIndex(self.index_block, self.index_str)),
                self.text.get_output_index().block_index,
                self.text.get_output_index().str_index,
                self.text.is_input(TextWidgetIndex(self.index_block, self.index_str)),
                self.text.get_input_index().block_index,
                self.text.get_input_index().str_index,
                self.text.is_reminder(TextWidgetIndex(self.index_block, self.index_str)),
                self.text.get_reminder_index().block_index,
                self.text.get_reminder_index().str_index,
                self.index_str,
                self.index_block)

    def setText(self, text):
        self.text = text


# 主窗口
class MainWindow(QMainWindow):
    def __init__(self, debug: bool = False):
        super().__init__()
        self.text = None
        self.tab = QtWidgets.QWidget()
        # self.text = TextWidget(QtWidgets.QWidget())
        self.centralwidget = QtWidgets.QWidget()
        self.verticalTabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.main_task = Task(parent=self, verticalTabWidget=self.verticalTabWidget)
        self.main = QtWidgets.QWidget()
        self._translate = QtCore.QCoreApplication.translate
        self.first = 0
        self.MainWindow = None
        self.tasks = []
        # layout = QtWidgets.QHBoxLayout()
        self.setObjectName("self")
        self.resize(800, 600)
        # self.setLayout(layout)
        self.set_up_menus(self)  # 菜单
        self.setCentralWidget(self.centralwidget)
        self.setWindowTitle(self._translate("self", "Terminal for Windows"))
        self.setCentralWidget(self.verticalTabWidget)
        # self.verticalTabWidget.currentChanged.connect(self.slot_task)
        self.verticalTabWidget.addTab(self.main_task.tab_page, "主面板")
        self.main_task.text_widget.textChanged.connect(self.debug_window_text_change)
        if debug:
            self.debug_window = debugWindow()
            self.debug_window.show()

    # 关于
    def about(self):
        self.incomplete_functions()

    # 创建新任务
    def new_task(self):
        new_task = Task(parent=self.MainWindow, verticalTabWidget=self.verticalTabWidget)
        self.tasks.append(new_task)
        self.verticalTabWidget.addTab(new_task.tab_page, 'name')

    def debug_window_text_change(self):
        self.debug_window.change(self.main_task.text_widget.debug)

    # 设置菜单
    def set_up_menus(self, main_window):
        # 文件路径插入
        menubar_insert_filepath = QAction('文件路径', main_window)
        menubar_insert_filepath.triggered.connect(self.MenubarInsertFilepath)
        # 文件夹路径插入
        menubar_insert_dirpath = QAction('文件夹路径', main_window)
        menubar_insert_dirpath.triggered.connect(self.MenubarInsertFolderpath)
        # 符号插入
        menubar_insert_symbol = QAction('符号', main_window)
        menubar_insert_symbol.triggered.connect(self.MenubarInsertSymbol)
        # 帮助
        menubar_usage = QAction('使用方法', main_window)
        menubar_usage.triggered.connect(self.usage)
        menubar_problem_solving = QAction('解决问题', main_window)
        menubar_problem_solving.triggered.connect(self.problem_solving)
        # 关于
        menubar_about = QAction('关于', main_window)
        menubar_about.triggered.connect(self.about)
        # 导入配置
        menubar_setting_loading = QAction('导入设置', main_window)
        menubar_setting_loading.triggered.connect(self.setting_loading)
        menubar = main_window.menuBar()  # 声明菜单栏
        # 插入
        menu_insert = menubar.addMenu('插入')
        menu_insert.addAction(menubar_insert_filepath)
        menu_insert.addAction(menubar_insert_dirpath)
        menu_insert.addAction(menubar_insert_symbol)
        # 设置
        menu_set = menubar.addMenu('设置')
        menu_set.addAction(menubar_about)
        menu_set.addAction(menubar_setting_loading)
        # 帮助
        menu_help = menubar.addMenu('帮助')
        menu_help.addAction(menubar_usage)
        menu_help.addAction(menubar_problem_solving)

    # 未完善的功能提示
    def incomplete_functions(self):
        QMessageBox.warning(QWidget(self.main),
                            '警告',
                            '功能未完善',
                            QMessageBox.Yes,
                            QMessageBox.Yes)

    # 菜单栏功能：插入文件路径
    def MenubarInsertFilepath(self):
        # self.checkTab()
        file_path, _ = QFileDialog.getOpenFileName(
            self.MainWindow,  # 父窗口对象
            "选择你要插入的文件的路径",  # 标题
            r"c:\\",  # 起始目录
            "所以类型 (*.*)")
        self.text.insertPlainText('"' + file_path + '"')

    # 菜单栏功能：插入文件夹路径
    def MenubarInsertFolderpath(self):
        # self.checkTab()
        dir_path = QFileDialog.getExistingDirectory(self.MainWindow, "选择你要插入的文件夹的路径")
        self.text.insertPlainText('"' + dir_path + '"')

    # 菜单栏功能：插入符号
    def MenubarInsertSymbol(self):
        self.incomplete_functions()

    # 解决问题
    def problem_solving(self):
        self.incomplete_functions()

    # 导入设置
    def setting_loading(self):
        self.incomplete_functions()

    # 使用方法
    def usage(self):
        self.incomplete_functions()


# debug窗口
class debugWindow(QDialog):
    # 初始化
    def __init__(self):
        super(debugWindow, self).__init__()
        self.resize(250, 300)
        self.centralwidget = QtWidgets.QWidget()
        self.text = QPlainTextEdit(parent=self)
        self._translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(self._translate("self", "debuger"))
        self.text.resize(250, 300)

    def change(self, new_value: str):
        self.text.setPlainText(new_value)


# 任务
class Task:
    # 初始化
    def __init__(self, parent, verticalTabWidget):
        self.CMDP: CMDPopen = CMDPopen()
        self.state: str = ''
        self.tab_page: QTabWidget = QTabWidget(parent=parent)
        self.text_widget: TextWidget = TextWidget(parent=parent, task=self)
        self.text: Text = Text(parent=self.text_widget)
        self.layout = QtWidgets.QHBoxLayout()
        self.verticalTabWidget = verticalTabWidget
        self.set_state('init')
        self.text_widget.setText(self.text)
        self.layout.addWidget(self.text_widget)
        self.tab_page.setLayout(self.layout)

    # 补全
    def completer(self, command):
        self.text.add_reminder(CommandCompleter.complete(command))

    # 运行
    def _run(self, CMD, name):
        self.state = 'run'
        self.verticalTabWidget.addTab(self.tab_page, name)
        self.CMDP.command(CMD)
        self.CMDPoutput()

    # CMD管道输出
    def CMDPoutput(self):
        self.text.setOutput(self.CMDP.wait(), TextWidgetIndex(self.text.get_output_index().block_index,
                                                              self.text.get_output_index().str_index))
        print(self.CMDP.wait())

    # CMD管道输入
    def CMDPinput(self, value):
        self.CMDP.command(value)

    # 重新运行
    def run_again(self):
        pass

    # 停止
    def stop(self):
        self.state = 'stop'
        self.CMDP.kill()

    def set_state(self, state, **kwargs):
        if state == 'init':
            self.state = 'init'
        elif state == 'wait':
            self.state = 'wait'
        elif state == 'run':
            self.state = 'run'
            self._run(self, **kwargs)
        elif state == 'stop':
            self.state = 'stop'
            self.CMDP.kill()
